﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Xna.Framework;
using System.ComponentModel;
using System.Collections;
using System.Windows.Ink;

namespace Pavilion.DesignerTool
{
    /// <summary>
    /// Interaction logic for DrawingPanel.xaml
    /// </summary>
    public partial class DrawingBoardView : UserControl
    {
        public static readonly DependencyProperty AnimationSelectionInfoProperty = DependencyProperty.Register("AnimationSelectionInfo", typeof(AnimationSelectionInfo), typeof(DrawingBoardView),
            new PropertyMetadata(new PropertyChangedCallback(AnimationSelectionInfoChanged)));
        public static readonly DependencyProperty DrawToolProperty = DependencyProperty.Register("DrawTool", typeof(IDrawTool), typeof(DrawingBoardView),
            new PropertyMetadata(new PropertyChangedCallback(DrawToolChanged)));
        public static readonly DependencyProperty ScaleProperty = DependencyProperty.Register("Scale", typeof(int), typeof(DrawingBoardView),
            new PropertyMetadata(new PropertyChangedCallback(ScaleChanged)));
        public static readonly DependencyProperty CurrentLayerProperty = DependencyProperty.Register("CurrentLayer", typeof(TextureData), typeof(DrawingBoardView),
            new PropertyMetadata(new PropertyChangedCallback(CurrentLayerChanged)));

        public DrawingBoardViewModel ViewModel { get; private set; }
        private bool _isMouseDown, isTabletMode;
        private TabletInput tabletInput;

        private System.Windows.Forms.MouseEventHandler mouseDownHandler, mouseMoveHandler, mouseUpHandler;
        private Action<System.Windows.Point> tabletPressedHandler, tabletRubbedHandler;
        private Action tabletReleasedHandler;

        public DrawingBoardView()
        {
            InitializeComponent();

            xnaView.XnaComponent = new DrawingBoardXnaComponent();
            this.DataContext = ViewModel = new DrawingBoardViewModel((DrawingBoardXnaComponent)xnaView.XnaComponent);

            xnaView.XnaWinFormsPanel.MouseMove += (s, e) => ViewModel.UpdatePenData(new System.Windows.Point(e.X, e.Y), 1);
            mouseDownHandler = (object sender, System.Windows.Forms.MouseEventArgs e) =>
            {
                if (e.Button != System.Windows.Forms.MouseButtons.Left)
                    return;

                _isMouseDown = true;
                ViewModel.UpdatePenData(new System.Windows.Point(e.X, e.Y), 1);
                ViewModel.BeginExecution();
            };

            mouseMoveHandler = (object sender, System.Windows.Forms.MouseEventArgs e) =>
            {
                if (e.Button != System.Windows.Forms.MouseButtons.Left)
                    return;

                _isMouseDown = true;
                ViewModel.UpdatePenData(new System.Windows.Point(e.X, e.Y), 1);
                ViewModel.Execute();
            };

            mouseUpHandler = (object sender, System.Windows.Forms.MouseEventArgs e) =>
            {
                if (_isMouseDown)
                {
                    if (e.Button != System.Windows.Forms.MouseButtons.Left)
                        return;

                    _isMouseDown = false;
                    ViewModel.UpdatePenData(new System.Windows.Point(e.X, e.Y), 1);
                    ViewModel.EndExecution();
                }
            };

            tabletPressedHandler = (System.Windows.Point position) =>
            {
                ViewModel.UpdatePenData(position, tabletInput.PressurePercentage);
                ViewModel.BeginExecution();
            };
            tabletRubbedHandler = (System.Windows.Point position) =>
            {
                ViewModel.UpdatePenData(position, tabletInput.PressurePercentage);
                ViewModel.Execute();
            };
            tabletReleasedHandler = () =>
            {
                ViewModel.UpdatePenData(tabletInput.CurrentPosition, tabletInput.PressurePercentage);
                ViewModel.EndExecution();
            };

            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                tabletInput = new TabletInput(xnaView.XnaWinFormsPanel);

                RegisterMouse();
            }

            xnaView.XnaWinFormsPanel.MouseLeave += (s, e) => ViewModel.SetCursorVisibility(false);
            xnaView.XnaWinFormsPanel.MouseEnter += (s, e) => ViewModel.SetCursorVisibility(true);
        }

        private void RegisterMouse()
        {
            xnaView.XnaWinFormsPanel.MouseDown += mouseDownHandler;
            xnaView.XnaWinFormsPanel.MouseMove += mouseMoveHandler;
            xnaView.XnaWinFormsPanel.MouseUp += mouseUpHandler;
        }

        private void UnregisteMouse()
        {
            xnaView.XnaWinFormsPanel.MouseDown -= mouseDownHandler;
            xnaView.XnaWinFormsPanel.MouseMove -= mouseMoveHandler;
            xnaView.XnaWinFormsPanel.MouseUp -= mouseUpHandler;
        }

        private void RegiesterTablet()
        {
            tabletInput.TabletPressed += tabletPressedHandler;
            tabletInput.TabletRubbed += tabletRubbedHandler;
            tabletInput.TabletReleased += tabletReleasedHandler;
        }

        private void UnregiesterTablet()
        {
            tabletInput.TabletPressed -= tabletPressedHandler;
            tabletInput.TabletRubbed -= tabletRubbedHandler;
            tabletInput.TabletReleased -= tabletReleasedHandler;
        }

        private bool _isLoaded;
        private void xnaView_Loaded(object sender, RoutedEventArgs e)
        {
            if (_isLoaded)
                return;

            if (!DesignerProperties.GetIsInDesignMode(this))
                ViewModel.SetScale(Scale);

            _isLoaded = true;
        }

        public AnimationSelectionInfo AnimationSelectionInfo
        {
            get { return (AnimationSelectionInfo)GetValue(AnimationSelectionInfoProperty); }
            set { SetValue(AnimationSelectionInfoProperty, value); }
        }

        public IDrawTool DrawTool
        {
            get { return (IDrawTool)GetValue(DrawToolProperty); }
            set { SetValue(DrawToolProperty, value); }
        }

        public int Scale
        {
            get { return (int)GetValue(ScaleProperty); }
            set { SetValue(ScaleProperty, value); }
        }

        public TextureData CurrentLayer
        {
            get { return (TextureData)GetValue(CurrentLayerProperty); }
            set { SetValue(CurrentLayerProperty, value); }
        }

        static private void AnimationSelectionInfoChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            (dependencyObject as DrawingBoardView).ViewModel.SetAnimationSelectionInfo((AnimationSelectionInfo)args.NewValue);
        }

        static private void DrawToolChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            (dependencyObject as DrawingBoardView).ViewModel.LoadDrawTool((IDrawTool)args.NewValue);
        }

        static private void ScaleChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            (dependencyObject as DrawingBoardView).ViewModel.SetScale((int)args.NewValue);
        }

        static private void CurrentLayerChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            (dependencyObject as DrawingBoardView).ViewModel.SetCurrentLayer((TextureData)args.NewValue);
        }

        internal void SwitchDrawingMode()
        {
            isTabletMode = !isTabletMode;

            if (isTabletMode)
            {
                UnregisteMouse();
                RegiesterTablet();
            }
            else
            {
                UnregiesterTablet();
                RegisterMouse();
            }
        }
    }
}
